# driver.mk
#
# Date: March 5, 2016
# Author: Brandon Perez
# Author: Jared Choi
#
# The Makefile for building the AXI DMA driver.

# Include guard for the Makefile
ifndef DRIVER_MAKEFILE_
DRIVER_MAKEFILE_=included

# Get the user defined variables, if they specified them
-include config.mk

# Get the libaxidma include paths
include library/library.mk

################################################################################
# Configuration
################################################################################

# Export user variables for the Kbuild file and kernel Makefile
ifdef CROSS_COMPILE
    export CROSS_COMPILE
endif
ifdef ARCH
    export ARCH
endif
ifneq ($(origin XILINX_DMA_INCLUDE_PATH_FIXUP),undefined)
    export XILINX_DMA_INCLUDE_PATH_FIXUP
endif

# When natively compiling, we can infer the kernel's source tree directory,
# if the user has not specified it.
ifndef CROSS_COMPILE
    KERNEL_VERSION = $(shell uname -r)
    KBUILD_DIR ?= /lib/modules/$(KERNEL_VERSION)/build/
endif

# The kernel symbols file, used to determine if the kernel has been updated
KERNEL_SYMS = $(KBUILD_DIR)/Module.symvers

# The list of source files for the driver. Export the names to the Kbuild file.
DRIVER_DIR = driver
export AXIDMA_FILES = axi_dma.c axidma_chrdev.c axidma_dma.c axidma.h \
		axidma_of.c
DRIVER_PATHS = $(addprefix $(DRIVER_DIR)/,$(AXIDMA_FILES))

# The kernel object files generated by compilation
export AXIDMA_MODULE_NAME = axidma
DRIVER_OBJECT = $(DRIVER_DIR)/$(AXIDMA_MODULE_NAME).ko
DRIVER_OUTPUT_OBJECT = $(OUTPUT_DIR)/$(AXIDMA_MODULE_NAME).ko

# Export the include directories to the Kbuild file, making sure the path is
# absolute, as the kernel Makefile is run in a different directory.
export AXIDMA_INC_DIRS = $(PWD)/$(LIBAXIDMA_INC_DIRS)

################################################################################
# Targets
################################################################################

# These targets don't correspond to actual generated files
.PHONY: driver driver_clean kbuild_def_check arch_def_check \
		kbuild_exists_check kbuild_built_check

# User-facing targets for compiling the driver
driver: $(DRIVER_OUTPUT_OBJECT)

# Compile the driver against the given kernel. The check targets are phony, so
# don't force this target to run because of them.
$(DRIVER_OBJECT): $(DRIVER_PATHS) $(KERNEL_SYMS) | kbuild_def_check \
			arch_def_check kbuild_exists_check kbuild_built_check \
			cross_compiler_check
	make -C $(KBUILD_DIR) M=$(PWD)/$(DRIVER_DIR) modules

# Copy the compiled driver to the specified output directory
$(DRIVER_OUTPUT_OBJECT): $(DRIVER_OBJECT) $(OUTPUT_DIR)
	@cp $< $@

# Clean up all the files generated by compiling the driver
driver_clean: | kbuild_def_check arch_def_check kbuild_exists_check
	rm -f $(DRIVER_OUTPUT_OBJECT)
	make -C $(KBUILD_DIR) SUBDIRS=$(PWD)/$(DRIVER_DIR) clean

# Check that KBUILD_DIR is explicitly specified when cross-compiling
kbuild_def_check:
ifndef KBUILD_DIR
	@printf "Error: The variable 'KBUILD_DIR' must be specified when "
	@printf "cross-compiling the driver.\n"
	@exit 1
endif

# Check that ARCH is defined when CROSS_COMPILE is specified
arch_def_check:
ifdef CROSS_COMPILE
ifndef ARCH
	@printf "Error: 'ARCH' must be specified when cross-compiling the driver.\n"
	@exit 1
endif
endif

# Check that the specified kernel source tree directory exists
kbuild_exists_check:
ifeq (,$(wildcard $(KBUILD_DIR)))
	@printf "Error: $(KBUILD_DIR): The kernel source tree does not exist.\n"
	@exit 1
endif

# Check that the kernel is built in the specified kernel source tree
kbuild_built_check:
ifeq (,$(wildcard $(KERNEL_SYMS)))
	@printf "Error: $(KBUILD_DIR): This is not a valid kernel build tree or "
	@printf "the kernel has not yet been built. The kernel must be built "
	@printf "before compiling the driver against it.\n"
	@exit 1
endif

endif # DRIVER_MAKEFILE_
